package server

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"

	"github.com/samaa/photosalesplus/backend/internal/config"
	"github.com/samaa/photosalesplus/backend/internal/handlers"
	"github.com/samaa/photosalesplus/backend/internal/middleware"
	"github.com/samaa/photosalesplus/backend/internal/repositories"
	"github.com/samaa/photosalesplus/backend/internal/routes"
	"github.com/samaa/photosalesplus/backend/internal/services"
)

type Server struct {
	cfg    *config.Config
	engine *gin.Engine
}

func New(cfg *config.Config, db *gorm.DB, redisClient *redis.Client) *Server {
	engine := gin.Default()

	userRepo := repositories.NewUserRepository(db)
	merchantRepo := repositories.NewMerchantRepository(db)
	productRepo := repositories.NewProductRepository(db)
	orderRepo := repositories.NewOrderRepository(db)
	mediaAssetRepo := repositories.NewMediaAssetRepository(db)

	userService := services.NewUserService(userRepo)
	authService := services.NewAuthService(cfg, redisClient, userService)
	merchantAuthService := services.NewMerchantAuthService(cfg, redisClient, merchantRepo)
	productService := services.NewProductService(productRepo, orderRepo)
	orderService := services.NewOrderService(orderRepo, userRepo, productRepo)
	uploadService := services.NewUploadService(cfg, mediaAssetRepo)
	assetHandler := handlers.NewAssetHandler(cfg, authService, userRepo, mediaAssetRepo, productRepo, orderRepo)

	// Ensure default merchant account (for initial login)
	if err := merchantAuthService.EnsureDefault(context.Background()); err != nil {
		log.Printf("failed to ensure default merchant: %v", err)
	}

	authHandler := handlers.NewAuthHandler(authService, userService)
	merchantAuthHandler := handlers.NewMerchantAuthHandler(merchantAuthService)
	productHandler := handlers.NewProductHandler(productService)
	orderHandler := handlers.NewOrderHandler(orderService)
	uploadHandler := handlers.NewUploadHandler(uploadService)

	authMiddleware := middleware.NewAuthMiddleware(authService)
	merchantAuthMiddleware := middleware.NewMerchantAuthMiddleware(merchantAuthService)

	routes.Register(engine, routes.Dependencies{
		AuthHandler:            authHandler,
		MerchantAuthHandler:    merchantAuthHandler,
		ProductHandler:         productHandler,
		OrderHandler:           orderHandler,
		UploadHandler:          uploadHandler,
		AssetHandler:           assetHandler,
		AuthMiddleware:         authMiddleware,
		MerchantAuthMiddleware: merchantAuthMiddleware,
		StorageDir:             cfg.StorageDir,
	})

	return &Server{
		cfg:    cfg,
		engine: engine,
	}
}

func (s *Server) Run() error {
	addr := fmt.Sprintf("%s:%s", s.cfg.AppHost, s.cfg.AppPort)
	srv := &http.Server{
		Addr:              addr,
		Handler:           s.engine,
		ReadTimeout:       10 * time.Second,
		WriteTimeout:      20 * time.Second,
		ReadHeaderTimeout: 5 * time.Second,
	}
	return srv.ListenAndServe()
}
